package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * @author zcf
 */
//定义切面类，实现公共字段自动填充
//切面类：切入点+通知
@Aspect
@Slf4j
public class AutoFillAspect {
    //切入点，匹配需要拦截的方法,是mapper包下的加了AtuoFill注解的方法
    @Pointcut("execution(* com.sky.mapper.*.*(..))&&@annotation(com.sky.annotation.AutoFill)")
    public void autoFillXxx(){}

    //通知
    //这里使用前置通知或者环绕都可以
    //前置通知
    @Before("autoFillXxx()")
    public void autoFill(JoinPoint joinPoint) throws Exception{
        log.info("开始自动填充");
        //1.获取当前拦截方法上注解里面的操作类型
        //1.1获取方法签名对象
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //1.2获取注解
        AutoFill annotation = signature.getMethod().getAnnotation(AutoFill.class);
        OperationType type = annotation.value();
        //2.获取当前拦截方法参数
        Object[] args = joinPoint.getArgs();
        if(ObjectUtils.isEmpty(args)){
            return;
        }
        Object arg = args[0];
        //可以看到当前不知道是什么类型，所以只能通过反射获取set赋值方法
        Method setCreateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
        Method setUpdateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
        Method setCreateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
        Method setUpdateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

        //根据类型开始赋值,参数一：要赋值的对象，参数二：要赋的值
        if(type == OperationType.INSERT){
            setCreateTime.invoke(arg,LocalDateTime.now());
            setCreateUser.invoke(arg,BaseContext.getCurrentId());
        }

        setUpdateTime.invoke(arg,LocalDateTime.now());
        setUpdateUser.invoke(arg,BaseContext.getCurrentId());
    }
}
